package com.chujian.system.sys.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.chujian.client.wx.WxMpUserClient;
import com.chujian.framework.core.base.BaseServiceImpl;
import com.chujian.framework.exception.MsgException;
import com.chujian.framework.util.mybatis.MybatisUs;
import com.chujian.base.ICols;
import com.chujian.sys.entity.SysDept;
import com.chujian.sys.entity.SysUser;
import com.chujian.sys.entity.SysUserLogin;
import com.chujian.sys.vo.SysUserSourceVo;
import com.chujian.wx.entity.WxMpUser;
import com.chujian.system.sys.mapper.SysUserMapper;
import com.chujian.system.sys.service.IPasswordGen;
import com.chujian.system.sys.service.SysDeptService;
import com.chujian.system.sys.service.SysUserLoginService;
import com.chujian.system.sys.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author yj
 * @since 2021/8/20 14:45
 */
@Service
@Slf4j
public class SysUserServiceImpl extends BaseServiceImpl<SysUserMapper, SysUser> implements SysUserService, ICols {

    // 缺省
    @Value("${chujian.system.default.password:111}")
    private String defaultPassword;

    @Autowired
    private SysDeptService deptService;
    @Autowired
    private IPasswordGen passwordGen;
    @Autowired
    private SysUserLoginService userLoginService;
    @Autowired
    private WxMpUserClient wxMpUserClient;
    @Autowired
    @Lazy
    private SysUserService userService;

    @Override
    public boolean beforeIns(SysUser data) {
        // ## 设置密码
        if (StringUtils.isEmpty(data.getPassword())) {
            genSaltAndPassword(data);
        }
        // ## 账号重复性校验
        if (StringUtils.isEmpty(data.getLoginName())) {
            this.checkExistAccount(data.getLoginName());
        }

        beforeInsOrUpd(data);
        return true;
    }

    @Override
    public boolean beforeUpd(SysUser data) {
        beforeInsOrUpd(data);
        return true;
    }

    @Override
    public void afterIns(SysUser data) {
        // + 保存后，如果没有生成账号，则将账号设置为ID
        if (StringUtils.isNotEmpty(data.getLoginName())) {
            this.updateById(new SysUser().setUserId(data.getUserId()).setLoginName("" + data.getUserId()));
        }
    }

    @Override
    public List<SysUser> listByUserAccount(String account) {
        return baseMapper.listByUserAccount(account);
    }

    @Override
    public SysUser getPureUserById(Long userId) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.eq(user_id, userId);
        SysUser user = this.getOne(wrapper);
        return user;
    }

    @Override
    public List<SysUser> getUsersByDeptId(Long deptId) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.eq(dept_id, deptId);
        List<SysUser> userList = this.list(wrapper);
        return userList;
    }

    @Override
    public void resetPassword(Long userId) {
        SysUser user = new SysUser().setUserId(userId);
        genSaltAndPassword(user);
        this.updateById(user);
    }

    @Override
    public SysUser getSimpleUserInfo(SysUser sysUser) {
        return new SysUser()
                .setUserId(sysUser.getUserId())
                .setUserName(sysUser.getUserName())
                .setMobile(sysUser.getMobile())
                .setEmail(sysUser.getEmail())
                .setSex(sysUser.getSex())
                .setBirth(sysUser.getBirth())
                .setAddr(sysUser.getAddr())
                .setAcId(sysUser.getAcId());
    }

    @Override
    public SysUser getUserWithWxInfo(Long userId) {
        SysUser user = this.getById(userId);
        // 小程序OPENID为空
        if (StringUtils.isEmpty(user.getWxMinipOpenId())) {
            SysUserLogin userLogin = userLoginService.getMaUserLoginByUserId(userId);
            if (null != userLogin) {
                userService.updateById(
                        new SysUser()
                                .setUserId(userId)
                                .setWxMinipOpenId(userLogin.getWxMinipOpenId())
                                .setWxUnionId(userLogin.getWxUnionId())
                                .setWxNickname(userLogin.getWxNickname())
                                .setWxGender(userLogin.getWxGender())
                                .setWxHeadUrl(userLogin.getWxHeadUrl())
                );
                user = this.getById(userId);
            }
        }
        // 公众号OPENID为空
        if (StringUtils.isNotEmpty(user.getWxUnionId()) && StringUtils.isEmpty(user.getWxMpOpenId())) {
            // 获取对应的公众号
            WxMpUser mpUser = wxMpUserClient.getMpUserByUnionId(user.getWxUnionId()).getData();
            if (null != mpUser) {
                userService.updateById(
                        new SysUser()
                                .setUserId(userId)
                                .setWxMpOpenId(mpUser.getOpenId())
                );
                user = this.getById(userId);
            }
        }
        return user;
    }

    @Override
    public void clearUserWxInfos(Long userId) {
        userService.update(
                new UpdateWrapper<SysUser>()
                        .set(wx_mp_open_id, null)
                        .set(wx_minip_open_id, null)
                        .set(wx_union_id, null)
                        .set(wx_nickname, null)
                        .set(wx_head_url, null)
                        .set(wx_gender, null)
                        .eq(user_id, userId)
        );
    }

    @Override
    public SysUser getByAccount(String loginName) {
        return this.getOne(
                new QueryWrapper<SysUser>().eq(login_name, loginName)
        );
    }

    @Override
    public boolean checkExistAccount(String loginName) {
        MybatisUs.execWithNoAc(ListUtil.toList(sys_user_table), "全局账号一致性检测", () -> {
            SysUser user = this.getByAccount(loginName);
            if (null != user) {
                throw new MsgException("账号 " + loginName + "已经存在");
            }
        });
        return false;
    }

    /**
     * 生成密码和盐
     *
     * @param user user
     */
    private void genSaltAndPassword(SysUser user) {
        String salt = RandomUtil.randomString(6);
        user.setPasswordSalt(salt);
        user.setPassword(passwordGen.genPassword(defaultPassword, salt));
    }

    private void beforeInsOrUpd(SysUser data) {
        // 设置搜索项
        data.setSearchInfo(joinSearchInfo(data.getUserName(), data.getPinYin(), data.getLoginName()));
    }

    private String joinSearchInfo(String... infos) {
        List<String> list = Arrays.stream(infos).filter(StringUtils::isNotEmpty)
                .collect(Collectors.toList());
        return CollUtil.join(list, "");
    }


    @Override
    @Transactional
    public SysUser saveSync(SysUserSourceVo sourceVo) {
        if (StringUtils.isEmpty(sourceVo.getSourceId())) {
            throw new MsgException("user.saveSync sourceId不可为空");
        }
        // # 查找部门
        if (StringUtils.isNotEmpty(sourceVo.getDeptSid())) {
            SysDept dept = deptService.tryCreDept(sourceVo.getDeptSid(), sourceVo.getDeptName());
            sourceVo.setDeptId(dept.getId());
        }
        // # 保存
        SysUser user = this.getBySourceIdWithLock(sourceVo.getSourceId());
        if (null == user) { // insert
            userService.ins(sourceVo);
        } else {
            sourceVo.setUserId(user.getUserId());
            userService.upd(sourceVo);
        }
        return user;
    }

    @Override
    public SysUser getBySourceId(String sourceId) {
        return this.getOne(new QueryWrapper<SysUser>().eq(source_id, sourceId));
    }

    @Override
    public SysUser getBySourceIdWithLock(String sourceId) {
        return this.getOne(new QueryWrapper<SysUser>().eq(source_id, sourceId).last(FOR_UPDATE_SQL));
    }

    @Override
    public Map<Serializable, String> getEchoData(Collection<Serializable> ids) {
        return this.listByIds(ids)
                .stream()
                .collect(Collectors.toMap(SysUser::getUserId, SysUser::getUserName));
    }
}

